<?php
namespace App\Http\Service;

use App\Exceptions\OrdinaryException;
use App\Traits\Third\TokenThird;

/**
 * 获取第三方登录信息逻辑层
 * @date 2018-11-15
 * @author zx
 */
class ThirdLoginService {
    use TokenThird;

    private static $_obj;

    /**
     * 第三方登录配置数组
     * @var array
     */
    private $_secerts;

    /**
     * 第三方登录配置名
     * @var array
     */
    private $_secretKeys;

    /**
     * 第三方登录APPID
     * @var string
     */
    private $_appId;

    /**
     * 第三方登录秘钥
     * @var string
     */
    private $_secret;

    /**
     * 授权类型
     * @var string
     */
    private $_grant_type;

    /**
     * 请求地址
     * @var string
     */
    private $_request_uri;

    public static function getInstance()
    {
        if(!(self::$_obj instanceof self))
            self::$_obj = new self();

        return self::$_obj;
    }

    //TODO: NOT NEW
    private function __construct()
    {
        $this->_secerts = config("secret");
        $this->_secretKeys = array_keys($this->_secerts);
    }

    /**
     * 获取第三方用户信息
     *
     * @param int $code code码,用来换取access_token
     * @param string state 来源
     * @author zx
     * @date 2018-11-15
     * @return mixed
     * @throws OrdinaryException
     */
    public function getThirdInfo(string $code, string $state)
    {
        if(!$state || !in_array($state, $this->_secretKeys))
            throw new OrdinaryException("来源有误!请核对后重试.", 500);
        //初始化参数
        $this->_appId = $this->_secerts[$state]['appid']??NULL;
        $this->_secret = $this->_secerts[$state]['secret']??NULL;
        $this->_grant_type = $this->_secerts[$state]['grant_type']??NULL;
        $this->_request_uri = $this->_secerts[$state]['uri']['request_uri']??NULL;

        $func = $state.'_third_id';
        $data = $this->$func($code);

        if(!$data) {
            throw new OrdinaryException("未知的错误导致获取失败", 500);
        }

        return $data;
    }

    /**
     * 微信小程序获取第三方ID
     *
     * @param string $code
     * @date 2018-11-16
     * @author zx
     * @return array
     */
    public function xcx_third_id(string $code):array
    {
        $params['appid'] = $this->_appId;
        $params['secret'] = $this->_secret;
        $params['js_code'] = $code;
        $params['grant_type'] = $this->_grant_type;

        $url = $this->_request_uri.'?'.http_build_query($params);

        $res = json_decode(curls($url), TRUE);
        if(isset($res['errcode']) && $res['errcode'] != 0) throw new OrdinaryException($res['errmsg'], 500);

        return $res?:[];
    }

    /**
     * 微信公众号获取第三方ID
     *
     * @param string $code
     * @date 2018-11-16
     * @author zx
     * @return array
     */
    public function gzh_third_id(string $code):array
    {
        $params['appid'] = $this->_appId;
        $params['secret'] = $this->_secret;
        $params['code'] = $code;
        $params['grant_type'] = $this->_grant_type;

        // 获取access_token
        $url = $this->_request_uri.'?'.http_build_query($params);

        $res = json_decode(curls($url), TRUE);

        $result = [];
        $func = function($access_token)use($res, &$result){
            $data['access_token'] = $access_token;
            $data['openid'] = $res['openid'];
            $data['lang'] = $this->_secerts['wechat']['lang'];
            $url = $this->_secerts['wechat']['uri']['userinfo_uri'].'?'.http_build_query($data);
            $result = json_decode(curls($url), TRUE);
        };
        $access_token = $this->getAccessToken();
        $func($access_token);
        if(isset($result['errcode'])) {
            $result = [];
            $access_token = $this->getAccessToken(TRUE);
            $func($access_token);
        }
        if(isset($result['errcode'])) throw new OrdinaryException("未知错误,获取用户信息失败", 500);

        return $result;
    }

    /**
     * qq获取第三方ID
     *
     * @param string $code
     * @date 2018-11-16
     * @author zx
     */
    public function qq_third_id(string $code):array
    {
        $params['grant_type'] = $this->_grant_type;
        $params['client_id'] = $this->_appId;
        $params['client_secret'] = $this->_secret;
        $params['code'] = $code;
        $params['redirect_uri'] = $this->_secerts['qq']['uri']['redirect_uri'];
        $url = $this->_secerts['qq']['uri']['token_uri'];
        //获取token字符串
        $jsonStr = curls($url, 1, $params);
        //提取access_token
        $arr = explode("&", $jsonStr);
        $tokenArr = [];
        $access_token_arr = [];
        foreach ( $arr as $key => $val ) {
            $tokenArr[] = explode("=", $val);
        }
        foreach ( $tokenArr as $key => $val ){
            $access_token_arr[$val[0]] = $val[1];
        }

        $data['access_token'] = $access_token_arr['access_token'];
        $str = curls($this->_request_uri, 1, $data);
        $jsonArr = json_decode(substr($str, strpos($str, '(')+1, -3), TRUE);
        if($jsonArr['openid']) {
            throw new OrdinaryException("未知错误,授权失败", 500);
        }

        $data['oauth_consumer_key'] = $this->_appId;
        $data['openid'] = $jsonArr['openid'];
        $url = $this->_secerts['qq']['uri']['userinfo_uri']."?".http_build_query($data);
        $info = json_decode(curls($url), TRUE);
        if (!$info || (isset($info['ret']) && $info['ret'] > 0)) {
            throw new OrdinaryException("未知错误,用户信息获取失败", 500);
        }
        $info['openid'] = $data['openid'];
        return $info;
    }

    /**
     * 微博登录
     *
     * @param string $code
     * @author zx
     * @date 2018-11-16
     * @return array
     */
    public function weibo_third_id(string $code):array
    {
        $params['client_id'] = $this->_appId;
        $params['client_secret'] = $this->_secret;
        $params['grant_type'] = $this->_grant_type;
        $params['redirect_uri'] = $this->_secerts['weibo']['uri']['redirect_uri'];
        $params['code'] = $code;
        $url = $this->_secerts['weibo']['uri']['token_uri']."?".http_build_query($params);

        $tokens = json_decode(curls($url),TRUE);  //获取token
        if (isset($tokens['error_code'])) throw new OrdinaryException("授权失败", 500);

        $data['uid'] = $tokens['uid'];
        $data['access_token'] = $tokens['access_token'];
        $info_url = $this->_request_uri.'?'.http_build_query($data);

        $res = json_decode(curls($info_url), TRUE); //获取用户信息

        return $res?:[];
    }

}